using System;
using System.IO;
using Seagull.Configuration;
using Seagull.Events;
using Seagull.Events.Drive;
using Seagull.Generic;
using Seagull.Model.Alerts;

namespace Seagull.DAL.DriveManagers
{
    public abstract class DriveManagerBase : IModule
    {
        public abstract DriveInfo Drive { get; }

        private readonly int _diskFreeSpaceQuotaGB;

        private RegistrationToken _eventRegistrationToken;

        protected DriveManagerBase(int diskFreeSpaceQuotaGB)
        {
            _diskFreeSpaceQuotaGB = diskFreeSpaceQuotaGB;
        }

        #region IModule Members

        public virtual void Start()
        {
            if(!_eventRegistrationToken.IsEmpty)
            {
                throw new InvalidOperationException(string.Format("{0} already started!", GetType().Name));
            }
            _eventRegistrationToken = NewMinuteEvent.Instance.Register(OnNewMinute);
        }

        public virtual void Stop()
        {
            NewMinuteEvent.Instance.UnRegister(_eventRegistrationToken);
            _eventRegistrationToken = RegistrationToken.Empty;
        }

        #endregion

        #region Update Used Space Percentage

        private int _lastUsedSpacePercentage = -1;

        public int UsedSpacePercentage
        {
            get
            {
                var value = 100;
                try
                {
                    var drive = Drive;
                    if(drive != null)
                    {
                        value = (int)(drive.UsedPercentage() * 100);
                    }
                }
                catch(IOException exception)
                {
                    OnGetUsedPercentageError(exception);
                }
                return value;
            }
        }

        private void OnNewMinute(DateTime time)
        {
            var currentUsedSpacePercentage = UsedSpacePercentage;
            if(currentUsedSpacePercentage != _lastUsedSpacePercentage)
            {
                _lastUsedSpacePercentage = currentUsedSpacePercentage;
                // BUG: Possibly the UI will not get the data if it starts too late
                OnDriveSpaceChanged(currentUsedSpacePercentage);
            }
            CheckFreeSpaceForAlert();
        }

        protected virtual void OnDriveSpaceChanged(int usedPercentage)
        {
        }

        #endregion

        #region Free Space Check and Alert

        private DateTime _lastTimeAlertPublished;

        private long FreeSpaceMB
        {
            get
            {
                long freeSpaceMB = 0;
                try
                {
                    var drive = Drive;
                    if(drive != null)
                    {
                        freeSpaceMB = drive.AvailableFreeSpace/1024/1024;
                    }
                }
                catch(IOException exception)
                {
                    OnGetUsedPercentageError(exception);
                }
                return freeSpaceMB;
            }
        }

        public void CheckFreeSpaceForAlert()
        {
            var freeSpaceMB = FreeSpaceMB;
            if(freeSpaceMB < _diskFreeSpaceQuotaGB * 1024 &&
                (DateTime.Now - _lastTimeAlertPublished).TotalMinutes > 1)
            {
                _lastTimeAlertPublished = DateTime.Now;
                OnDiskFull(freeSpaceMB);
            }
        }

        protected virtual void OnDiskFull(long freeSpaceMB)
        {
        }

        #endregion

        protected virtual void OnGetUsedPercentageError(IOException exception)
        {
        }
    }
}